#include <fstream>
#include <random>
#include <thread>

#include <bthread/bthread.h>
#include <glog/logging.h>
#include <gtest/gtest.h>

#include "hawking/indexlib/index_config.pb.h"
#include "doc/document_creator.h"
#include "index/deletion_index/deletion_index_indexer.h"

using namespace hawking::indexlib;
std::uniform_int_distribution<int32_t> dis(1, 1000000);
std::default_random_engine e{std::random_device{}()};

DEFINE_uint32(write_count, 0, "for dump test");
std::unordered_map<DocId, DocId> old2new_map;

void* DeletionWrite(void* arg) {
    DeletionMapIndexer* deletion_indexer = reinterpret_cast<DeletionMapIndexer*>(arg);

    while (1) {
        DocId fake_doc_id = static_cast<DocId>(dis(e));
        deletion_indexer->Delete(fake_doc_id);
        bthread_usleep(2000 * 1000);
    }
}

void* DeletionRead(void* arg) {
    DeletionMapIndexer* deletion_indexer = reinterpret_cast<DeletionMapIndexer*>(arg);
    std::unordered_set<DocId> deletion_set;

    while (1) {
        for (DocId doc_id = 1; doc_id < 1000000; ++doc_id) {
            if (deletion_indexer->IsDeleted(doc_id) &&
                deletion_set.find(doc_id) == deletion_set.end()) {
                LOG(INFO) << "doc_id " << doc_id << " is deleted";
                deletion_set.insert(doc_id);
            }
        }

        bthread_usleep(1 * 1000);
    }
    
    return nullptr;
}

TEST(deletion_test, read_and_write) {
    DeletionMapIndexer deletion_indexer;
    deletion_indexer.Init();

    bthread_t deletor;
    bthread_start_background(&deletor, nullptr, DeletionWrite, &deletion_indexer);

    std::vector<bthread_t> readers;
    readers.reserve(128);
    for (size_t idx = 0; idx < readers.capacity(); ++idx) {
        readers.emplace_back();
        bthread_start_background(&readers.back(), nullptr, DeletionRead, &deletion_indexer);
    }

    bthread_join(deletor, nullptr);
    for (auto reader : readers) {
        bthread_join(reader, nullptr);
    }
}

int main(int argc, char* argv[]) {
    ::testing::InitGoogleTest(&argc, argv);
    ::google::ParseCommandLineFlags(&argc, &argv, true);
    srand(static_cast<unsigned>(time(0)));
    return RUN_ALL_TESTS();
}
